package leo.peersim.paxos;

import leo.peersim.common.LogicalClock;
import peersim.core.Node;

/**
 * 
 * @author leo
 * @version June 18, 2009
 */
public abstract class PaxosMessage {

	private final Node _senderNode;
	private final LogicalClock _senderLogicalClock;
	private final LogicalClock _ballot;
	
	public PaxosMessage(Node senderNode, LogicalClock senderLogicalClock, LogicalClock ballot) {
		this._senderLogicalClock = senderLogicalClock;
		this._ballot = ballot;
		this._senderNode = senderNode;
	}
	
	public LogicalClock getSenderLogicalClock() {
		return this._senderLogicalClock;
	}
	
	public LogicalClock getBallotId() {
		return this._ballot;
	}
	
	public Node getSenderNode() {
		return this._senderNode;
	}
}

/**
 * <p>Prepare message is sent by a {@link Proposer} agent, which is trying to become
 * the new group's Leader, to {@link Acceptor} agents. They are expected to reply with
 * either a {@link Promise} message in the case of the proposal has been accepted or
 * with a {@link Refuse} message otherwise.</p>
 * 
 * @author leo
 * @version
 */
class Prepare extends PaxosMessage {

	public Prepare(Node senderNode, LogicalClock senderLogicalClock, LogicalClock ballot) {
		super(senderNode, senderLogicalClock, ballot);
	}

}

/**
 * Promise
 * 
 * @author leo
 * @version
 */
class Promise extends PaxosMessage {
	
	private final LogicalClock _latestPhase2Ballot;
	private final long _latestAcceptedValue;

	public Promise(Node senderNode, LogicalClock senderLogicalClock, LogicalClock ballot, LogicalClock latestPhase2Ballot, long latestAcceptedValue) {
		super(senderNode, senderLogicalClock, ballot);
		this._latestPhase2Ballot = latestPhase2Ballot;
		this._latestAcceptedValue = latestAcceptedValue;
	}
	
	public long getLatestAcceptedValue() {
		return _latestAcceptedValue;
	}
	
	public LogicalClock getLatestPhase2Ballot() {
		return this._latestPhase2Ballot;
	}
	
}

/**
 * Refuse
 * 
 * @author leo
 * @version June 19, 2009
 */
class Refuse extends PaxosMessage {
	
	private final LogicalClock _latestAcceptedPhaseABallot;

	public Refuse(Node senderNode, LogicalClock senderLogicalClock, LogicalClock ballotId, LogicalClock lastAcceptedPhaseABallot) {
		super(senderNode, senderLogicalClock, ballotId);
		this._latestAcceptedPhaseABallot = lastAcceptedPhaseABallot;
	}
	
	public LogicalClock getLatestAcceptedPhaseABallot() {
		return this._latestAcceptedPhaseABallot;
	}
	
}

/**
 * Reject
 * 
 * @author leo
 * @version June 19, 2009
 */
class Reject extends PaxosMessage {
	
	private final LogicalClock _latestAcceptedPhaseABallot;

	public Reject(Node senderNode, LogicalClock senderLogicalClock, LogicalClock ballot, LogicalClock lastAcceptedPhaseABallot) {
		super(senderNode, senderLogicalClock, ballot);
		this._latestAcceptedPhaseABallot = lastAcceptedPhaseABallot;
	}
	
	public LogicalClock getLatestAcceptedPhaseABallot() {
		return this._latestAcceptedPhaseABallot;
	}
	
}

/**
 * Accept
 * 
 * @author leo
 * @version June 20, 2009
 */
class Accept extends PaxosMessage {
	
	private final long _proposal;
	private final String _opName;

	public Accept(Node senderNode, LogicalClock senderLogicalClock, LogicalClock ballot, String opName, long proposal) {
		super(senderNode, senderLogicalClock, ballot);
		this._proposal = proposal;
		this._opName = opName;
	}
	
	public long getProposal() {
		return this._proposal;
	}
	
	public String getOpName() {
		return this._opName;
	}
	
}

/**
 * Decide
 * 
 * @author leo
 * @version June 19, 2009
 */
class Decide extends PaxosMessage {
	
	private final long _decidedValue;
	private final String _opName;

	public Decide(Node senderNode, LogicalClock senderLogicalClock, LogicalClock ballot, String opName, long decidedValue) {
		super(senderNode, senderLogicalClock, ballot);
		this._decidedValue = decidedValue;
		this._opName = opName;
	}
	
	public long getDecidedValue() {
		return this._decidedValue;
	}
	
	public String getOpName() {
		return this._opName;
	}
	
}